package middleware.p2p;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.Random;

import javax.activation.MimetypesFileTypeMap;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.GroupLayout.Alignment;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.filechooser.FileFilter;

import middleware.p2p.log.MiddlewareLogEvent;
import middleware.p2p.log.MiddlewareMonitorEvent;
import middleware.p2p.log.VectorClock;

import org.apache.log4j.Logger;

/**
 * 	Frame principale della GUI.
 * 	Permette di creare workflow da inserire nella coda.
 * 	@see WFQueueManager
 * 	@see Workflow
 * 	@see UI
 */
public class P2PMainFrame extends JFrame{
	/**
	 * 	Campo necessario alla serializzazione
	 */
	private static final long serialVersionUID = 7111083242759532800L;
	/**
	 * 	Pannello contenente i dati di un singolo Task all'interno di un Workflow.
	 */
	private class TaskPanel extends JPanel {
		/**
		 * 	Campo necessario alla serializzazione
		 */
		private static final long serialVersionUID = -7619477261593254052L;
		private int id;
		final private JTextField path;
		private JTextField param;		
		public TaskPanel(int id) {
			super(new BorderLayout());
			this.id=id;
			this.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));			
			JPanel innerPanel=new JPanel(new BorderLayout(5,5));
			JPanel topPannel=new JPanel(new GridLayout(2,1));
			JLabel taskId=new JLabel("Task "+id);			
			Font tFont=new Font(taskId.getName(), Font.BOLD, taskId.getFont().getSize());
			taskId.setFont(tFont);
			topPannel.add(taskId);			
			topPannel.add(new JLabel("File:"));
			innerPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
			//innerPanel.add(new JLabel(Integer.toString(id)),BorderLayout.WEST);
			innerPanel.add(topPannel,BorderLayout.NORTH);
			path=new JTextField();
			JButton browseButton = new JButton("Sfoglia");
			browseButton.addMouseListener(new MouseAdapter() {
					public void mouseClicked(MouseEvent e) {
						JFileChooser chooser=new JFileChooser();
						chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
						chooser.setAcceptAllFileFilterUsed(false);
						chooser.setFileFilter(new FileFilter() {							
							public String getDescription() {								
								return "Script Sh o Eseguibili";
							}							
							public boolean accept(File f) {
								if (f.isDirectory()) {
									return true;
								} else {
							        int dotPos = f.getName().lastIndexOf(".");
							        String extension="";
							        if (dotPos!=-1) {							        	
							        	extension = f.getName().substring(dotPos);
							        }
									if (extension.equalsIgnoreCase(".sh")) {
										return true;
									} else {										
										String type=new MimetypesFileTypeMap().getContentType(f);
										if (type.equals("application/octet-stream")&&((extension.equals(""))||(extension.equals(".exe")))) {
											return true;
										} else {
											return false;
										}
									}
								}
							}
						});
						if (chooser.showDialog(null, "Scegli")==JFileChooser.APPROVE_OPTION) {
							path.setText(chooser.getSelectedFile().getAbsolutePath());
						}
					}
			});
			innerPanel.add(path,BorderLayout.CENTER);
			innerPanel.add(browseButton,BorderLayout.EAST);
			JPanel bottomPanel=new JPanel(new BorderLayout(5,0));
			bottomPanel.add(new JLabel("Parametri: "),BorderLayout.WEST);
			param=new JTextField();
			bottomPanel.add(param,BorderLayout.CENTER);
			innerPanel.add(bottomPanel,BorderLayout.SOUTH);
			this.add(innerPanel,BorderLayout.CENTER);
			this.setMaximumSize(new Dimension(330,40));
		}
		/**
		 * 	Metodo per estrarre un TaskDescriptor dai dati contenuti nel Pannello.
		 * 	@return Il task descriptor generato, null se non è stato possibile generare il descrittore.
		 */
		public TaskDescriptor getTaskDescriptor() {
			if (!path.getText().isEmpty()) {
				TaskDescriptor tk=new TaskDescriptor();
				tk.setID(id);
				tk.setLink(this.path.getText());
				File f=new File(this.path.getText());
				TaskTYPE taskTYPE;
				if (f.isDirectory()) {
					return null;
				} else {
			        int dotPos = f.getName().lastIndexOf(".");
			        String extension="";
			        if (dotPos!=-1) {							        	
			        	extension = f.getName().substring(dotPos);
			        }
					if (extension.equalsIgnoreCase(".sh")) {
						taskTYPE=TaskTYPE.scriptBash;
					} else {										
						String type=new MimetypesFileTypeMap().getContentType(f);
						if (type.equals("application/octet-stream")&&((extension.equals(""))||(extension.equals(".exe")))) {
							taskTYPE=TaskTYPE.Executable;
						} else {
							return null;
						}
					}
				}
				tk.setType(taskTYPE);
				String command="";
				if (taskTYPE==TaskTYPE.scriptBash) {
					command="sh ";
				}
				command+=tk.getLink()+" "+this.param.getText();
				tk.setCommand(command);
				return tk;
			} else {
				return null;
			}
		}
	}	
	private WFQueueManager queue;
	private ParallelGroup hPar;	
	private GroupLayout.SequentialGroup vGroup;
	private GroupLayout layout;
	private JLabel workflowLabel;	
	private JPanel tasksPanel;
	private JScrollPane scroll;
	private JButton addTaskButton;
	private void addTask() {
		Random rnd=new Random();
		int i=rnd.nextInt(Integer.MAX_VALUE);
		TaskPanel task=new TaskPanel(i);		
		hPar.addComponent(task);
		vGroup.addGroup(layout.createParallelGroup(Alignment.CENTER).addComponent(task));
		scroll.setViewportView(tasksPanel);
	}
	private void runWorkflow() {
		Workflow wf=new Workflow();
		wf.setID(Integer.parseInt(this.workflowLabel.getText().substring(this.workflowLabel.getText().lastIndexOf("#")+1)));
		int numTask=0;
		for (int i=0;i<this.tasksPanel.getComponentCount();i++) {
			Component tComp=this.tasksPanel.getComponent(i);
			if (tComp.getClass().getName().equals(TaskPanel.class.getName())) {
				TaskPanel pan=(TaskPanel)tComp;
				TaskDescriptor td=pan.getTaskDescriptor();
				if (td!=null) {
					wf.addTask(td);
					//System.out.println("TD #"+td.getID()+" command:"+td.getCommand()+" link:"+td.getLink()+" type:"+((td.getType()==TaskTYPE.Executable)?"Exec":"Script"));
					numTask++;
				}
			}			
		}
		if (numTask!=0) {
			MiddlewareMonitorEvent monitorEvent=new MiddlewareMonitorEvent();
			queue.enqueue(wf,monitorEvent);
			VectorClock logLocalClock= CORE.getLogVectorClock().addEventToClock(CORE.getComponentId());
			VectorClock monitorLocalClock= CORE.getMonitorVectorClock().addEventToClock(CORE.getComponentId());
			Logger.getLogger(this.getClass()).info(new MiddlewareLogEvent(logLocalClock,"Workflow "+wf.getID()+" inserito nella coda."));
			monitorEvent.setVclock(monitorLocalClock);
			monitorEvent.setComponentID(CORE.getComponentId());
			Logger.getLogger(CORE.monitorWFQueueName).info(monitorEvent.getQueueContent());
			Logger.getLogger(CORE.monitorWFQueueStatusName).info(monitorEvent);
			generateWorkflow();
			JOptionPane.showMessageDialog(this, "Workflow inserito in coda","Creazione Workflow",JOptionPane.INFORMATION_MESSAGE);
			this.tasksPanel.removeAll();
			this.scroll.setViewportView(tasksPanel);
		} else {
			JOptionPane.showMessageDialog(this,"Inserire almeno un task valido","Creazione Workflow",JOptionPane.ERROR_MESSAGE);
		}
	}
	private void generateWorkflow() {
		Random rnd=new Random();
		int i=rnd.nextInt(Integer.MAX_VALUE);
		this.workflowLabel.setText("Workflow #"+i);
	}
	/**
	 * 	Costruttore principale del Frame.
	 * 	Inizializza tutti i componenti grafici.
	 * 	@param 	queue	La coda in cui verranno inseriti i Workflow.
	 */
	public P2PMainFrame(WFQueueManager queue) {
		super("P2P Middleware GUI");
		this.queue=queue;
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(500,350);
		JPanel mainPanel=new JPanel(new BorderLayout(10,10));
		mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
		tasksPanel=new JPanel();	
		layout = new GroupLayout(tasksPanel);
        tasksPanel.setLayout(layout);		
		layout.setAutoCreateGaps(true);		 
		layout.setAutoCreateContainerGaps(true);
		GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
		this.hPar=layout.createParallelGroup();
		this.vGroup = layout.createSequentialGroup();
		hGroup.addGroup(hPar);		   
		layout.setHorizontalGroup(hGroup);				  
		layout.setVerticalGroup(vGroup);
		scroll = new JScrollPane(tasksPanel);		
		mainPanel.add(scroll,BorderLayout.CENTER);
		workflowLabel=new JLabel();
		mainPanel.add(workflowLabel,BorderLayout.NORTH);
		this.generateWorkflow();
		JPanel buttonPanel=new JPanel(new BorderLayout());
		//BoxLayout boxLayout= new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS);
		//buttonPanel.setLayout(boxLayout);
		JPanel innerButtonPanel=new JPanel(new GridLayout(2,1,10,10));		
		addTaskButton=new JButton("Aggiungi Task");
		addTaskButton.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				addTask();
			}
		});
		innerButtonPanel.add(addTaskButton);		
		JButton runButton= new JButton("Esegui");
		runButton.addMouseListener(new MouseAdapter(){
			public void mouseClicked(MouseEvent e) {
				runWorkflow();
			}
		});
		innerButtonPanel.add(runButton);
		buttonPanel.add(innerButtonPanel,BorderLayout.NORTH);
		buttonPanel.add(Box.createVerticalGlue(),BorderLayout.CENTER);
		mainPanel.add(buttonPanel,BorderLayout.EAST);
		this.getContentPane().add(mainPanel);
		Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
		int x=(int)((screenSize.width-this.getWidth())/2);
		int y=(int)((screenSize.height-this.getHeight())/2);
		this.setLocation(x, y);
	}	
}